package core;
import java.util.HashMap;
import java.util.Iterator;

public class FordFulkersonUtils {

	// Setting up Maps for both edges and vertices
	private static HashMap<Edge, EdgeData> edgesMap = new HashMap<Edge, EdgeData>();
	private static HashMap<Vertex, VertexData> verticesMap = new HashMap<Vertex, VertexData>();
	private static Vertex source;
	private static Vertex sink;
	
	public static Vertex getSource() {
		return source;
	}

	public static void setSource(Vertex source) {
		FordFulkersonUtils.source = source;
	}

	public static Vertex getSink() {
		return sink;
	}

	public static void setSink(Vertex sink) {
		FordFulkersonUtils.sink = sink;
	}

	public static HashMap<Edge, EdgeData> getEdgesMap() {
		return edgesMap;
	}

	public static void setEdgesMap(HashMap<Edge, EdgeData> edgesMap) {
		FordFulkersonUtils.edgesMap = edgesMap;
	}

	public static HashMap<Vertex, VertexData> getVerticesMap() {
		return verticesMap;
	}

	public static void setVerticesMap(HashMap<Vertex, VertexData> verticesMap) {
		FordFulkersonUtils.verticesMap = verticesMap;
	}
	
	public static void unVisitVertices(){
		Iterator<VertexData> verticesIterator = FordFulkersonUtils.verticesMap.values().iterator();
		while(verticesIterator.hasNext()){
			verticesIterator.next().setVisited(false);
		}
	}

	public static double augment(double flow, SimpleGraph path) {
		double bottleneck = getBottleneck(path);
		for (int i = 0; i < path.edgeList.size(); i++) {
			Edge edge = (Edge) path.edgeList.get(i);
			EdgeData edgeData = FordFulkersonUtils.getEdgesMap().get(edge);
			edgeData.increasFlowBy(bottleneck);
		}
		return bottleneck;
	}

	public static void swapVertices(Edge edge) {
		EdgeData data = FordFulkersonUtils.getEdgesMap().get(edge);
		FordFulkersonUtils.getEdgesMap().remove(edge);
		edge = new Edge(edge.getSecondEndpoint(), edge.getFirstEndpoint(),
				edge.getData(), edge.getName());
		FordFulkersonUtils.getEdgesMap().put(edge, data);
	}

	public static double getBottleneck(SimpleGraph path) {
		@SuppressWarnings("unchecked")
		Iterator<Edge> edgesIterator = path.edges();
		double bottleneck = Double.MAX_VALUE;
		while (edgesIterator.hasNext()) {
			Edge edge = edgesIterator.next();
			EdgeData data = FordFulkersonUtils.getEdgesMap().get(edge);
			if (bottleneck > data.getCapacity()) {
				bottleneck = data.getCapacity();
			}
		}
		return bottleneck;
	}

	public static double getDelta(SimpleGraph graph, Vertex from) {
		@SuppressWarnings("unchecked")
		Iterator<Edge> egdesIterator = graph.incidentEdges(from);
		double maxCapacity = 0;
		double delta = 1;
		while (egdesIterator.hasNext()) {
			EdgeData edgeData = FordFulkersonUtils.getEdgesMap().get(egdesIterator.next());
			if (edgeData.getCapacity() > maxCapacity) {
				maxCapacity = edgeData.getCapacity();
			}
		}

		while (delta * 2 <= maxCapacity) {
			delta *= 2;
		}

		return delta;
	}

	public static void init(SimpleGraph graph) {
		@SuppressWarnings("unchecked")
		Iterator<Edge> edgesIterator = graph.edges();
		while (edgesIterator.hasNext()) {
			Edge edge = edgesIterator.next();
			EdgeData data = new EdgeData();
			data.setCapacity((Double.parseDouble(edge.getData().toString())));
			FordFulkersonUtils.getEdgesMap().put(edge, data);
		}
		@SuppressWarnings("unchecked")
		Iterator<Vertex> verticesIterator = graph.vertices();
		while (verticesIterator.hasNext()) {
			Vertex vertex = verticesIterator.next();
			VertexData data = new VertexData();
			FordFulkersonUtils.getVerticesMap().put(vertex, data);
			if(vertex.getName().toString().equalsIgnoreCase("s")){setSource(vertex);}
			if(vertex.getName().toString().equalsIgnoreCase("t")){setSink(vertex);}
		}
	}
}
